

class Upgrade {
	constructor() {
		this.maskEl = {}
		this.popupEl = {}
		this.confirmBtnEl = null
		this.cancelBtnEl = null
		this.progressEl = null
		this.progressDownloadEl = null
		this.progressTextEl = null
		this.progressDescEl = null
		this.downloadingProgress = 0
		this.screenWidth = 0;
		this.screenHeight = 0;
		this.popupHeight = 230;
		this.popupWidth = 300;
		this.viewWidth = 260;
		this.descrTop = 130;
		this.viewPadding = 20;
		this.titleHeight = 30;
		this.textHeight = 18;
		this.textSpace = 10;
		this.popupContent = []
		this.apkUrl = '';
		// 默认配置
		this.config = {
			androidType: 0,				// 安卓升级方式，0 应用内更新 / 1 去应用商店更新， 默认应用内更新
			packageName:'',				// android 包名，upType=1 时必填 
			appleId:'',					// ios 应用 id，app store中获取，ios必填
			timer:24,					// 主动检测间隔小时，默认24
			icon: '',					// 自定义弹窗图标，默认使用内置Base64图片
			iconTop: 40,				// 图标镂空顶部多高（如火箭头突出部分）
			iconWidth: 80,				// 图标宽度
			iconHeight: 80,				// 图标高度
			contentHeight: 160,			// 内容高度
			title: '发现新版本',			// 弹窗标题，默认发现新版本
			confirmText: '立即更新',		// 弹窗确定文字
			cancelTtext: '稍后再说',		// 弹窗取消文字
			confirmBgColor: '#409eff',	// 弹窗确定背景颜色
			showCancel: true,			// 弹窗是否显示取消，true / false
			titleAlign: 'left',			// 弹窗标题对齐方式，left / center
			descriAlign: 'left'			// 更新描述对齐方式，left / center
		}
	}
	
	
	// 设置升级配置
	setConfig(options){
		Object.assign(this.config, options);
	}
	
	/**
	 * 监测APP版本升级
	 * @param {boolean} manual 是否用户手动监测升级，默认为false，表示app自动监测升级
	 */
	upgrade(fn, manual){
		this.requestVersion = fn;
		if(manual){
			this.judgeTimeStamp();
		}else{
			this.getVersion();
		}
	}
	
	// 判断时间戳检测是否更新
	judgeTimeStamp(){
		uni.getStorage({
			key:'appUpdateTime',
			success:(res)=>{
				const timeLength=1000*60*60*this.config.timer;
				const currTimeStamp=new Date().getTime();
				if((res.data+timeLength)<currTimeStamp){
					this.getVersion();
				}
			},
			fail:()=>{
				// 获取缓存失败(第一次进入APP)检测更新
				this.getVersion();
			}
		})
	}
	
	// 获取当前版本信息
	getVersion(){
		this.setDefaultIcon();
		plus.runtime.getProperty(plus.runtime.appid,(wgtinfo)=>{
			this.requestVersion(wgtinfo.version, res=>{
				/* 
				res.status 是否有新版本，0无，1有
				res.url 新版 apk 地址
				res.description 更新日志
				 */
				if(res.status===1){
					this.apkUrl = res.url || '';
					this.config.showCancel = !res.force;
					const description=res.description || '';
					this.show(description);
				}
			})
			this.storageTimeStamp()
		});
	}
	
	// 设置弹窗图标
	setDefaultIcon() {
		var bitmap = new plus.nativeObj.Bitmap('upgrade_default');
		var imageStr = 
			''
		bitmap.loadBase64Data(imageStr, function() {
			bitmap.save("_pic/upgrade.png", {}, function(i) {
				bitmap.clear();
			}, function(e) {
				bitmap.clear();
			});
		}, function() {
			bitmap.clear();
		});
	}
	
	// 缓存检测更新的时间戳
	storageTimeStamp(){
		const currTimeStamp=new Date().getTime();
		uni.setStorage({
			key:'appUpdateTime',
			data:currTimeStamp
		})
	}
	
	// 显示
	show(changelog) {
		this.drawView(changelog)
		this.maskEl.show()
		this.popupEl.show()
		this.confirmBtnEl.show()
		if(this.cancelBtnEl)  this.cancelBtnEl.show()
	}
	
	// 隐藏
	hide() {
		this.maskEl.hide()
		this.popupEl.hide()
		this.confirmBtnEl.hide()
		if(this.cancelBtnEl)  this.cancelBtnEl.hide()
	}
	
	// 绘制
	drawView(changelog) {
		this.screenHeight = plus.screen.resolutionHeight;
		this.screenWidth = plus.screen.resolutionWidth;
		this.popupWidth = this.screenWidth * 0.8;
		this.viewWidth = this.popupWidth - this.viewPadding * 2;
		this.popupContent = [];
	
		if (this.config.icon) {
			this.popupContent.push({
				id: 'logo',
				tag: 'img',
				src: this.config.icon,
				position: {
					top: '0px',
					left: (this.popupWidth - this.config.iconWidth) / 2 + 'px',
					width: this.config.iconWidth + 'px',
					height: this.config.iconHeight + 'px'
				}
			});
		} else {
			// 默认图标宽整个面板
			this.config.iconWidth = this.popupWidth;
			this.config.iconHeight = this.config.iconWidth * 0.55;
			this.config.iconTop = this.config.iconWidth * 0.18;
			this.popupContent.push({
				id: 'logo',
				tag: 'img',
				src: '_pic/upgrade.png',
				position: {
					top: '0px',
					left: '0px',
					width: this.config.iconWidth + 'px',
					height: this.config.iconHeight + 'px'
				}
			});
		}
		this.popupHeight = this.viewPadding * 2 + this.config.iconHeight + this.config.contentHeight;
		this.descrTop = this.viewPadding + this.config.iconHeight + this.titleHeight;
	
		// 标题
		if (this.config.title) {
			this.popupContent.push({
				id: 'title',
				tag: 'font',
				text: this.config.title,
				textStyles: {
					size: '18px',
					color: '#333',
					weight: 'bold',
					align: this.config.titleAlign
				},
				position: {
					top: this.descrTop - this.titleHeight - this.textSpace + 'px',
					left: this.viewPadding + 'px',
					width: this.viewWidth + 'px',
					height: this.titleHeight + 'px'
				}
			})
		} else {
			this.descrTop -= this.titleHeight;
		}
	
		this.drawText(changelog)
		this.drawBox()
	}
	
	// 描述内容
	drawText(changelog) {
		if (!changelog) return [];
		const textArr = changelog.split('')
		const len = textArr.length;
		let prevNode = 0;
		let nodeWidth = 0;
		let letterWidth = 0;
		const chineseWidth = 14;
		const otherWidth = 7;
		let rowText = [];
	
		for (let i = 0; i < len; i++) {
			// 包含中文
			if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
				// 包含字母
				let textWidth = ''
				if (letterWidth > 0) {
					textWidth = nodeWidth + chineseWidth + letterWidth * otherWidth;
					letterWidth = 0;
				} else {
					// 不含字母
					textWidth = nodeWidth + chineseWidth;
				}
	
				if (textWidth > this.viewWidth) {
					rowArrText(i, chineseWidth)
				} else {
					nodeWidth = textWidth;
				}
			} else {
				// 不含中文
				// 包含换行符
				if (/\n/g.test(textArr[i])) {
					rowArrText(i, 0, 1)
					letterWidth = 0;
				} else if (textArr[i] == '\\' && textArr[i + 1] == 'n') {
					rowArrText(i, 0, 2)
					letterWidth = 0;
				} else if (/[a-zA-Z0-9]/g.test(textArr[i])) {
					// 包含字母数字
					letterWidth += 1;
					const textWidth = nodeWidth + letterWidth * otherWidth;
					if (textWidth > this.viewWidth) {
						const preNode = i + 1 - letterWidth;
						rowArrText(preNode, letterWidth * otherWidth)
						letterWidth = 0;
					}
				} else {
					if (nodeWidth + otherWidth > this.viewWidth) {
						rowArrText(i, otherWidth)
					} else {
						nodeWidth += otherWidth;
					}
				}
			}
		}
	
		if (prevNode < len) {
			rowArrText(len, -1)
		}
		this.drawDesc(rowText)
	
		function rowArrText(i, nWidth = 0, type = 0) {
			const typeVal = type > 0 ? 'break' : 'text';
	
			rowText.push({
				type: typeVal,
				content: changelog.substring(prevNode, i)
			})
	
			if (nWidth >= 0) {
				prevNode = i + type;
				nodeWidth = nWidth;
			}
		}
	}
	
	// 描述
	drawDesc(rowText) {
		rowText.forEach((item, index) => {
			if (index > 0) {
				this.descrTop += this.textHeight;
				this.popupHeight += this.textHeight;
			}
	
			this.popupContent.push({
				id: 'content' + index + 1,
				tag: 'font',
				text: item.content,
				textStyles: {
					size: '14px',
					color: '#666',
					align: this.config.descriAlign
				},
				position: {
					top: this.descrTop + 'px',
					left: this.viewPadding + 'px',
					width: this.viewWidth + 'px',
					height: this.textHeight + 'px'
				}
			})
	
			if (item.type == 'break') {
				this.descrTop += this.textSpace;
				this.popupHeight += this.textSpace;
			}
		})
	}
	
	// 确认按钮
	drawConfirmBtn(id, width, text, left = this.viewPadding) {
		const btnWidth = this.config.showCancel ? (this.viewWidth - this.viewPadding) / 2 : this.viewWidth
		const btnLeft = this.config.showCancel ?  this.screenWidth * 0.1 + 2 * this.viewPadding + btnWidth : this.screenWidth * 0.1 + this.viewPadding
		const el = new plus.nativeObj.View('confirmBox', {
			tag: 'rect',
			left: btnLeft,
			bottom: (this.screenHeight - this.popupHeight) / 2 + this.viewPadding,
			height: '40px',
			width: btnWidth
		});
			
		// 白色背景
		el.drawRect({
			color: this.config.confirmBgColor,
			radius: '6px',
		}, {
			top: 0,
			height: '40px',
		});
		el.drawText(this.config.confirmText, {
			top: 0,
			left: 0,
			width: btnWidth,
			height: '40px'
		}, {
			size: '14px',
			color: '#ffffff',
			align: 'center'
		})
		el.addEventListener('click', () => this.checkOs())
		
		this.confirmBtnEl = el
	}
	
	// 取消按钮
	drawCancelBtn(id, width, text, left = this.viewPadding) {
		if(!this.config.showCancel) return null
		
		const btnWidth = (this.viewWidth - this.viewPadding) / 2
		const btnLeft = this.screenWidth * 0.1 + this.viewPadding
		const el = new plus.nativeObj.View('confirmBox', {
			tag: 'rect',
			left: btnLeft,
			bottom: (this.screenHeight - this.popupHeight) / 2 + this.viewPadding,
			height: '40px',
			width: btnWidth
		});
			
		// 白色背景
		el.drawRect({
			color: '#f0f0f0',
			radius: '6px'
		}, {
			top: 0,
			height: '40px',
		});
		el.drawText(this.config.cancelTtext, {
			top: 0,
			left: 0,
			width: btnWidth,
			height: '40px'
		}, {
			size: '14px',
			color: '#666666',
			align: 'center'
		})
		
		el.addEventListener('click', () => this.hide())
		
		this.cancelBtnEl = el
	}
	
	// 进度条
	drawProgress() {
		const btnWidth = this.viewWidth * 0.9
		const progressWidth = 0
		const btnLeft = this.screenWidth * 0.1 + this.viewPadding
		const el = new plus.nativeObj.View('downLoadingProgress', {
			tag: 'rect',
			left: btnLeft,
			bottom: (this.screenHeight - this.popupHeight) / 2 + 48,
			height: '10px',
			width: btnWidth
		});
		el.drawRect({
			color: '#f0f0f0',
			radius: '5px',
		}, {
			top: 0,
			height: '10px',
		})
		
		const progressDownloadEl = new plus.nativeObj.View('downLoadedProgress', {
			tag: 'rect',
			left: btnLeft,
			bottom: (this.screenHeight - this.popupHeight) / 2 + 48,
			height: '10px',
			width: 0
		});
		
		progressDownloadEl.drawRect({
			color: this.config.confirmBgColor,
			radius: '5px',
		}, {
			top: 0,
			height: '10px',
		})
		
		const textEl = new plus.nativeObj.View('downLoadingProgressText', {
			tag: 'rect',
			left: btnLeft + btnWidth,
			bottom: (this.screenHeight - this.popupHeight) / 2 + 45,
			height: '14px',
			width: this.viewWidth * 0.2
		});
		
		textEl.drawText('0%', {
			top: 0,
			left: 10,
			height: '12px',
		}, {
			size: '12px',
			color: '#333',
			align: 'left'
		})
		
		const descEl = new plus.nativeObj.View('downLoadingProgressDesc', {
			tag: 'rect',
			left: btnLeft,
			bottom: (this.screenHeight - this.popupHeight) / 2 + 20,
			height: '14px',
			width: this.viewWidth
		});
		
		descEl.drawText('安装包下载中，请稍后...', {
			top: 0,
			left: 0,
			height: '12px',
		}, {
			size: '12px',
			color: '#333',
			align: 'center'
		})
		
		this.progressEl = el
		this.progressDownloadEl = progressDownloadEl
		this.progressTextEl = textEl
		this.progressDescEl = descEl
	}
	// 内容框
	drawBox() {
		this.maskEl = new plus.nativeObj.View('maskEl', {
			top: '0px',
			left: '0px',
			width: '100%',
			height: '100%',
			backgroundColor: 'rgba(0,0,0,0.5)'
		});
	
		this.popupEl = new plus.nativeObj.View('popupEl', {
			tag: 'rect',
			top: (this.screenHeight - this.popupHeight) / 2 + 'px',
			left: '10%',
			height: this.popupHeight + 'px',
			width: '80%'
		});
	
		// 白色背景
		this.popupEl.drawRect({
			color: '#ffffff',
			radius: '8px'
		}, {
			top: this.config.iconTop + 'px',
			height: this.popupHeight - this.config.iconTop + 'px'
		});
	
		this.popupEl.draw(this.popupContent);
		
		this.drawConfirmBtn()
		this.drawCancelBtn()
		this.drawProgress()
	}
	
	// 检测平台
	checkOs(){
		uni.getSystemInfo({
			success:(res) => {
				if(res.osName=="android"){
					if(this.config.androidType == 1 && this.config.packageName){
						plus.runtime.openURL('market://details?id='+this.config.packageName)
					}else{
						this.downloadInstallApp()
					}
				}else if(osName=='ios' && this.config.appleId){
					// apple id 在 app conection 上传的位置可以看到 https://appstoreconnect.apple.com
					plus.runtime.launchApplication({
						action: `itms-apps://itunes.apple.com/cn/app/id${this.config.appleId}?mt=8`
					}, function(err) {
						uni.showToast({
							title:err.message,
							icon:'none'
						})
					})
				}
			}  
		})
	}
	
	// 下载更新
	downloadInstallApp(){
		const dtask = plus.downloader.createDownload(this.apkUrl, {}, function (d,status){
			// 下载完成  
			if (status == 200){
				plus.runtime.install(plus.io.convertLocalFileSystemURL(d.filename),{}, function() {
						plus.runtime.restart();
					}, function(error){  
					uni.showToast({  
						title: '安装失败',
						icon:'none'
					});  
				})
			}else{
				uni.showToast({
					title: '更新失败',
					icon:'none'
				});
			}
		});
		this.downloadProgress(dtask)
	}
	// 开始下载
	showProgress() {
		this.confirmBtnEl.hide()
		if(this.cancelBtnEl) this.cancelBtnEl.hide()
		this.downloadingProgress = 0
		this.drawProgress()
		this.progressEl.show()
		this.progressDownloadEl.show()
		this.progressTextEl.show()
		this.progressDescEl.show()
	}
	
	setProgress(value) {
		this.progressDownloadEl.setStyle({width: this.viewWidth * 0.9 * parseFloat(value / 100)})
		this.progressTextEl.reset()
		this.progressTextEl.drawText(value + '%', {
			top: 0,
			left: 10,
			height: '12px',
		}, {
			size: '12px',
			color: '#333',
			align: 'left'
		})
	}
	
	// 下载进度
	downloadProgress(dtask){
		let _this = this
		try{
			dtask.start(); //开启下载任务
			_this.showProgress()
			_this.downloadingProgress = 0
			dtask.addEventListener('statechanged',function(task,status){
				// 给下载任务设置监听
				switch(task.state){
					case 1:
						console.log('正在下载')
						break;
					case 2:
						console.log('已连接到服务器')
						break;
					case 3:
						console.log(task.downloadedSize + '-' + task.totalSize)
						let prg=parseInt((parseFloat(task.downloadedSize)/parseFloat(task.totalSize))*100);
						if(prg !== _this.downloadingProgress) {
							_this.downloadingProgress = prg
							_this.setProgress(_this.downloadingProgress)
						}
						break;
					case 4:
						// 下载完成
						console.log('下载完成')
						break;
				}
			})
		}catch(e){
			plus.nativeUI.closeWaiting();
			uni.showToast({
				title: '更新失败',
				icon:'none'
			})
		}
	}
}


export default new Upgrade()